# coding=utf8
from typing import List, Optional

from pyjvm.classfile.attrs import AttributeInfo
from pyjvm.classfile.clsmember import FieldInfo
from pyjvm.classfile.constpool import *
from pyjvm.classfile.clstype import *
from pyjvm.utils import iter_readable


class ClassFile:
    MAGIC = b'\xca\xfe\xba\xbe'

    def __init__(self):
        self.magic: u4 = None
        self.minor_version: Optional[int] = None
        self.major_version: Optional[int] = None
        self.const_pool: Optional[ConstantPool] = None
        self.access_flags: u2 = None
        self.this_class_idx: u2 = None
        self.super_class_idx: u2 = None
        self.interface_idx_list: Optional[List[u2]] = None
        self.fields: Optional[List[FieldInfo]] = None
        self.methods: Optional[List[FieldInfo]] = None
        self.attributes: Optional[List[AttributeInfo]] = None
        self.__class_name: Optional[str] = None
        self.__super_class_name: Optional[str] = None
        self.__interface_names: Optional[List[str]] = None
        self.__package_name: Optional[str] = None

    @property
    def interface_names(self):
        if self.__interface_names is None:
            self.__interface_names = [
                self.const_pool.info_at_u2(u2idx).class_name
                for u2idx in self.interface_idx_list
            ]
        return self.__interface_names

    @property
    def super_class_name(self):
        if self.super_class_idx is None:
            return None
        if self.__super_class_name is None:
            info: ConstantClassInfo = self.const_pool.info_at_u2(self.super_class_idx)
            if info is None:  # java.lang.Object 没有父类
                self.super_class_idx = None
                return None
            self.__super_class_name = info.class_name
        return self.__super_class_name

    @property
    def class_name(self):
        if self.__class_name is None:
            info: ConstantClassInfo = self.const_pool.info_at_u2(self.this_class_idx)
            self.__class_name = info.class_name
        return self.__class_name

    @property
    def package_name(self):
        if self.__package_name is None:
            name = self.class_name
            pos = name.rfind('/')
            self.__package_name = '' if pos == -1 else name[:pos]
        return self.__package_name

    def __str__(self):
        return '''ClassFile[
            magic: %s,
            minor_version: %s,
            major_version: %s,
            constant_pool: %s,
            access_flags: %s,
            this_class: %s,
            super_class: %s,
            interfaces: %s,
            fields: %s,
            methods: %s,
            attributes: %s,
        ]''' % (self.magic, self.minor_version, self.major_version,
                self.const_pool, self.access_flags, self.this_class_idx,
                self.super_class_idx,
                iter_readable(self.interface_idx_list), iter_readable(self.fields),
                iter_readable(self.methods), iter_readable(self.attributes))


__all__ = ['ClassFile']
